/*
Blackjack[二十一点]

One Player Simple Blackjack[单人简单二十一点]
	* Hit and Stand only, (no double, split or insurance)[*仅拿牌和停牌，（没有加倍，分牌或保险）]
	* Dealer stands on soft 17[]

* Are there less than 17 cards in the deck?
	Note:
		AFAIK, the most cards for 2 players possible is 16:
		player hits to 21 ( A A A A 2 2 2 2 3 3 3 )
		dealer hits to 19 ( 3 4 4 4 4 )
	- True:
		* Shuffle deck.

* Is player wallet <= 1?
	- True:
		* Exit Game, player loses
* Bet = 0
* While player bet is 0
	* Ask player how much to bet
	* convert to int
	* Error converting to int?
		- True:
			* bet = 0
	* Is bet > player wallet?
		- True:
			* bet = 0
	* Is bet less than 0?
		- True:
			* Bet = 0
* Take Bet from player wallet
* Deal 2 cards to Dealer and player
* Does dealer have Ace + 10 K Q J ?
		* Does player have Ace + 10 K Q J?
			- True:
				* Show all cards
				* Push.
				* Return bet.
				* Next hand
			- False:
				* Show all cards.
				* Loss.
				* Next hand
* Does player have Ace + 10 K Q J?
	- True:
		* Player win.
		* Bet = Bet * 1.5, round down to lowest integer
		* Put winnings in player wallet.
		* Next Hand.
* Show 1 dealer card to player
* Show both player cards
* While player total < 21
	* Ask player "Hit or Stand"
	* If hit:
		* Deal card to player
		* Next loop
	* If stand:
		* exit loop
* Is player total > 21?
	- True:
		* Loss.
		* Next hand.
* Show dealer's 2nd card
* While dealer total < 17
	* Deal card to dealer
* Is dealer total > 21
	- True:
		* Win
		* Double bet and return to player's wallet
		* next hand
* Is player total == dealer total?
	- True:
		* Push
		* Return bet
		* Next hand.
* Is player total > dealer total?
	- True:
		* Win
		* Double bet and return to player wallet.
		* Return bet
		* Next Hand
	- False:
		* Loss
		* Next hand.

*phew*
That's a lot of rules.

*/

package main

import (
	"fmt"
	//"os"
	"strconv"

	"blackjack/deck"
)

// getString gets an arbitrary string from the user with a prompt.
// getString通过提示从用户获取任意字符串。
func getString(prompt string) string {
	fmt.Print(prompt)
	var input string
	fmt.Scanln(&input)
	return input
}

// getInteger gets an arbitrary int from the user with a prompt.
// Retries until a valid integer is entered.
/**
getInteger通过提示从用户获取任意int。
重试，直到输入有效整数。
**/
func getInteger(prompt string) int {
	valid := true
	input := getString(prompt)
	integer, err := strconv.Atoi(input)
	if err != nil {
		valid = false
	}
	for valid == false {
		fmt.Println("Can't convert your answer into an integer.[无法将您的答案转换为整数]")
		input = getString(prompt)
		integer, err = strconv.Atoi(input)
		if err == nil {
			valid = true
		}
	}
	return integer
}

// getBet gets an amount from user and removes the bet from the wallet
// Retries until a valid bet is entered.
/**
getBet从用户处获取金额并从钱包中减去赌注
重试，直到输入有效的赌注。
**/
func getBet(wallet *float64) int {
	bet := 0
	valid := false
	for valid == false {
		valid = true
		bet = getInteger("你想下注多少（5的倍数递增）？")
		if bet < 5 {
			valid = false
		}
		if float64(bet) > *wallet {
			valid = false
		}
		if bet%5 != 0 {
			valid = false //赌注不是5的倍数
		}
		if valid == false {
			fmt.Println("赌注必须是5的倍数")
		}
	}
	*wallet = *wallet - float64(bet)
	return bet
}

// getPlayerAction determines what the player will do
// TODO: Implement Double and Split
/**
getPlayerAction决定玩家将做什么
TODO:实现Double和Split
**/
func getPlayerAction() string {
	validInput := false
	input := ""
	for validInput == false {
		input = getString("[H]it or [S]tand? ") //命令行输入
		if input == "hit" || input == "Hit" || input == "H" || input == "h" {
			validInput = true
			input = "H"
		}
		if input == "stand" || input == "Stand" || input == "S" || input == "s" {
			validInput = true
			input = "S"
		}
		if validInput == false {
			fmt.Println("[无效选项。h拿牌或s停牌]")
		}
	}
	return input
}

// handTotal returns the numerical value of a Blackjack hand
// handTotal返回21点手牌数值
func handTotal(hand []deck.Card) int {
	total := 0        //统计手牌点数
	numberOfAces := 0 //统计A牌的个数
	for _, card := range hand {
		//判断A牌，点数+1
		if card.Value.Name == "Ace" {
			numberOfAces = numberOfAces + 1
		} else {
			//Facecard对J、Q、K、A返回true，对所有其他返回false
			if card.Facecard() {
				total = total + 10 //J,Q,K,A是10点
			} else {
				total = total + card.Value.Value //累加点数
			}
		}
	}

	//在多副牌组中，一手牌上可能有多个Ace（超过4个）]
	if numberOfAces > 0 {
		// All but the last Ace must be a one, because 11 + 11 = 22 (bust)[除最后一个Ace外，其他所有Ace都必须是1，因为11+11=22（爆了）]
		// This loop shouldn't run if there's only one Ace[如果只有一个Ace，这个循环不应该运行]
		for numberOfAces > 1 {
			total = total + 1
			numberOfAces = numberOfAces - 1
		}
		// There should now only be one Ace[现在应该只有一个Ace]
		// if the last Ace being 11 doesn't cause a bust, make it an 11[如果最后一个Ace是11并没有导致爆，那就把它变成11]
		if total+11 > 21 {
			total = total + 1
		} else {
			// If 11 doesn't cause a bust, make it worth 11[如果11不会导致爆，那就值11]
			total = total + 11
		}
	}
	return total
}

// Returns true if a hand is bust / over 21
// 如果手牌打破/超过21，则返回true
func isBust(hand []deck.Card) bool {
	if handTotal(hand) > 21 {
		return true
	}
	return false
}

// Returns true if a hand is a Blacjack (Ace + [10 | K | Q | J])
// 如果手牌是21点，则返回true
func isBlackjack(hand []deck.Card) bool {
	// A Blackjack is exactly one Ace and Exactly one 10, K, Q, or A
	// A 21点正好是一个Ace和一个10、K、Q或A
	if len(hand) != 2 {
		return false //2张手牌
	}
	// 在goplaycards库中，值从2枚举到14，14是Ace
	// J = 11, Q = 12, K = 13, Ace = 14[先判断第1张是不是A,再判断第2张是不是10]
	if hand[0].Value.Name == "Ace" {
		if hand[1].Value.Value >= 10 && hand[1].Value.Value <= 13 {
			return true
		}
	}
	// J = 11, Q = 12, K = 13, Ace = 14[先判断第2张是不是A,再判断第1张是不是10]
	if hand[1].Value.Name == "Ace" {
		if hand[0].Value.Value >= 10 && hand[0].Value.Value <= 13 {
			return true
		}
	}
	return false
}

func printHand(hand []deck.Card) {
	for _, card := range hand {
		fmt.Printf("%s  ", card.ToStr())
	}
	fmt.Printf(" Total: %d\n", handTotal(hand))
}

//打印出玩家手牌
func printPlayerHand(hand []deck.Card) {
	fmt.Printf("Player Hand: ")
	printHand(hand)
}

//打印出庄家手牌
func printDealerHand(hand []deck.Card, hideFirst bool) {
	fmt.Printf("Dealer Hand: ")
	if hideFirst {
		fmt.Printf("XX  %s  \n", hand[1].ToStr())
	} else {
		printHand(hand)
	}
}

func main() {
	wallet := 1000.00 //默认开局钱包
	bet := 0          //下赌注
	MinBet := 5.0     //最小赌注
	var d deck.Deck   //实例化卡牌
	d.Initialize()    //创建一副牌
	d.Shuffle()       //洗牌{[{{Hearts ♥} {Ten 10}} {{Spades ♠} {Three 3}} {{Clubs ♣} {Three 3}}...
	// fmt.Printf("%v \n", d)
	// return
	// 当玩家仍然有足够的钱下注时
	for wallet > MinBet {
		fmt.Println("=============================================================")
		fmt.Printf("%d cards left in the deck[牌组中剩余的牌].\n", d.CardsLeft())
		if d.CardsLeft() < 17 {
			// 如果少于17张，你必须洗牌]
			fmt.Println("重新洗牌...")
			d.Initialize()
			d.Shuffle()
			fmt.Printf("桌面剩余%d张牌].\n", d.CardsLeft())
		}
		fmt.Printf("你钱包余额 %.2f 。\n", wallet)
		bet = getBet(&wallet) //钱包-减去赌注
		fmt.Printf("\n 你的赌注: %d\n", bet)

		// draw the initial hands[画出最初的手牌]
		playerHand, err := d.Draw(2) //玩家2张牌
		if err != nil {
			panic(err)
		}
		dealerHand, err := d.Draw(2) //庄家2张牌
		if err != nil {
			panic(err)
		}

		// Handle all Blackjack[处理所有21点]
		if isBlackjack(dealerHand) || isBlackjack(playerHand) {
			printPlayerHand(playerHand)        //打印出手牌
			printDealerHand(dealerHand, false) //打印出手牌并隐藏第一张

			if isBlackjack(dealerHand) && isBlackjack(playerHand) {
				fmt.Println("庄和闲都是Blackjack，平局！")
				wallet = wallet + float64(bet)
				continue
			}

			if isBlackjack(dealerHand) {
				fmt.Println("庄家Blackjack，这局玩家输了。")
				continue
			}

			if isBlackjack(playerHand) {
				winnings := float64(bet) * 2.5 //玩家是Blackjack，加注2.5倍
				fmt.Printf("玩家Blackjack. 赢了 %.2f。\n", winnings)
				wallet = wallet + winnings
				continue
			}
		}

		// 玩家拿牌或停牌。。。
		playerDone := false
		for playerDone == false {
			printPlayerHand(playerHand)
			printDealerHand(dealerHand, true)
			action := getPlayerAction() //获取玩家的操作
			if action == "H" {
				drawnCards, err := d.Draw(1) //拿牌
				if err != nil {
					panic(err)
				}
				playerHand = append(playerHand, drawnCards[0]) //重新组合手牌
				// 是否爆了
				if isBust(playerHand) {
					printPlayerHand(playerHand) //打印出玩家手牌
					fmt.Println("Bust")
					playerDone = true
				}
			}
			if action == "S" {
				playerDone = true
			}
		}
		if isBust(playerHand) == true {
			continue
		}
		dealerDone := false
		for dealerDone == false {
			if handTotal(dealerHand) >= 17 {
				dealerDone = true
				continue
			}
			drawnCards, err := d.Draw(1)
			if err != nil {
				panic(err)
			}
			dealerHand = append(dealerHand, drawnCards[0])
		}
		printDealerHand(dealerHand, false)

		if handTotal(dealerHand) > 21 {
			fmt.Println("庄家爆了  玩家赢了！")
			wallet = wallet + float64(bet*2) //2倍赌注
			continue
		}

		if handTotal(playerHand) > handTotal(dealerHand) {
			fmt.Println("玩家点数大，玩家赢了！")
			wallet = wallet + float64(bet*2)
			continue
		}

		if handTotal(playerHand) == handTotal(dealerHand) {
			fmt.Println("Push[平局].")
			wallet = wallet + float64(bet)
			continue
		}

		if handTotal(playerHand) < handTotal(dealerHand) {
			fmt.Println("庄家赢了！")
			continue
		}
		fmt.Println("确定获胜者时出现问题")
	}
	fmt.Println("你没钱了!")
	return
}
